package rattlesnake.callback.core;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import rattlesnake.callback.aop.annotation.Handler;
import rattlesnake.callback.config.LoggerConfig;
import rattlesnake.callback.config.impl.CallbackProperties;
import rattlesnake.callback.core.cache.RedisCache;
import rattlesnake.callback.manager.CategoryInfo;
import rattlesnake.callback.server.HandlerAdapter;
import rattlesnake.callback.server.NettyServer2;
import rattlesnake.callback.server.handler.DefaultMethHandler;
import rattlesnake.callback.util.ClassUtil;
import rattlesnake.callback.util.HttpAsyncUtil;
import rattlesnake.callback.util.ObjectUtil;

import java.io.File;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @Package: rattlesnake.callback.core
 * @Description: 包装所有预处理信息
 * @author: liuxin
 * @date: 17/4/11 下午5:32
 */
public class NettyBootAppcation {
    private static final Logger logger = LoggerFactory.getLogger(NettyBootAppcation.class);
    private static final Map<String, Object> beanMap = new HashMap<>();
    //初始化的时候使用注解，把处理器和url和具体处理器添加
    private static final Map<String, HandlerAdapter> handlerMap = new HashMap<>();
    private static Set<Class<?>> classSet = new HashSet<Class<?>>();
    private static Set<Object> handlers = new HashSet<Object>();
    private static final Map<String, String> categoryUrl = new HashMap<String, String>();


    //初始化日志配置
    static {
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        JoranConfigurator configurator = new JoranConfigurator();
        configurator.setContext(lc);
        File externalConfigFile = new File(LoggerConfig.LOGGERCONFIG);
        if (ObjectUtils.isEmpty(externalConfigFile)) {
            logger.error("日志配置文件不存在...");
            System.exit(0);//退出
        }
        lc.reset();
        try {
            configurator.doConfigure(LoggerConfig.LOGGERCONFIG);
        } catch (JoranException je) {
            logger.error("加载配置日志配置失败");
            throw new RuntimeException("加载配置日志配置失败", je);
        }
        initialization();//初始化
    }

    public static void initialization() {
        initializationBeanMap();
        initializationHandler();
        categoryBindHandler();
        initializationCategoryUrl();
        callBackInfo();
    }

    /**
     * 初始化所有的class文件
     * 初始化bean实体
     */
    public static void initializationBeanMap() {
        classSet = ClassUtil.getClasses("rattlesnake.callback", true);
        for (Class cls : classSet) {
            try {
                beanMap.put(cls.getName(), cls);
            } catch (Exception e) {
                logger.error("初始化bean容器失败...");
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 初始化所有handler注解标记的处理器
     */
    public static void initializationHandler() {
        boolean flag = false;
        for (Class cls : classSet) {
            flag = ClassUtil.hasClassAnnotation(cls, Handler.class);
            if (flag) {
                try {
                    handlers.add(cls.newInstance());
                } catch (Exception e) {
                    logger.error("初始化Handler容器失败...");
                    throw new RuntimeException(e);
                }

            }
        }
    }

    public static void initializationCategoryUrl() {
        Class cls = CategoryInfo.class;
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            try {
                String key = field.getName().toLowerCase();
                String value = String.valueOf(field.get(field.getName()));
                categoryUrl.put(key, value);
                logger.info("品类服务请求地址绑定:{}->{}", key, value);
            } catch (IllegalAccessException iae) {
                logger.error("品类网络地址初始化错误");
                throw new RuntimeException(iae);
            }

        }
    }

    /**
     * 获得处理器，handler上面的注解
     * 获得里面的url地址，然后绑定
     * //绑定url服务和对应的处理器，
     * shenghuojiaofei->CommonMethHandler
     * fft->CommonMethHandler
     */
    public static void categoryBindHandler() {
        for (Object obj : handlers) {
            Handler handler = ClassUtil.getClassAnnotation(obj.getClass(), Handler.class);
            String[] categorys = handler.value();
            for (String str : categorys) {
                handlerMap.put(str, (HandlerAdapter) obj);
                logger.info("品类处理器绑定:{}->{}", str, obj.getClass().getName());
            }
        }
    }

    public static void run() {
        Integer port = CallbackProperties.getServerPort();
        NettyServer2.run(port);
    }


    /**
     * 根据url地址找到对象的处理器
     * 如果没有找到，就返回默认的处理器，返回404，和提示
     *
     * @param categoryUrl
     * @return
     */
    public static HandlerAdapter getHandlerByCategoryName(String categoryUrl) {
        HandlerAdapter handlerAdapter = handlerMap.get(categoryUrl);
        if (ObjectUtil.isEmpty(handlerAdapter)) {
            handlerAdapter = new DefaultMethHandler();
        }
        return handlerAdapter;
    }

    /**
     * 返回各品类的请求地址
     *
     * @return
     */
    public static Map<String, String> getCategoryUrl() {
        return categoryUrl;
    }

    /**
     * 程序启动第一次，检查redis的连接情况,插入连接通知提示
     * 启动完成后自动移除连接提示信息
     */
    public static void callBackInfo() {
        Class cls = RedisCache.class;
        RedisCache redisCache = null;
        try {
            redisCache = (RedisCache) ((Class) beanMap.get(cls.getName())).newInstance();

        } catch (Exception e) {
            System.out.println(e);
        }
        redisCache.set("test", RedisCache.REDIS_CONN_SUCCESS);
        logger.debug("Test the connection jedis:{}", redisCache.get("test"));
    }

    /**
     * 从系统中获得缓存
     *
     * @return
     */
    public static RedisCache getRedisCache() {
        Class cls = RedisCache.class;
        RedisCache redisCache = null;
        try {
            redisCache = (RedisCache) ((Class) beanMap.get(cls.getName())).newInstance();

        } catch (Exception e) {
            logger.debug("获取RedisCache失败...");
            throw new RuntimeException(e);
        }
        return redisCache;
    }

    /**
     * 从bean容器中获取，制定的bean类型
     *
     * @param cls
     * @param <T>
     * @return
     */
    public static <T> Object getBean(Class<T> cls) {
        T obj = null;
        try {
            obj = (T) ((Class) beanMap.get(cls.getName())).newInstance();
        } catch (Exception e) {
            logger.debug("获取制定Bean失败...");
            throw new RuntimeException(e);
        }
        return obj;
    }

}
